import json
import re

from django.contrib.auth import login, logout, authenticate
from django.http import JsonResponse
from django.shortcuts import render
from django_redis import get_redis_connection

from apps.users.models import User

# Create your views here.
from django.views import View
from celery_tasks.email.tasks import send_verify_email
from apps.users.utils import generate_verify_email_url
from meiduo_practice.utils.secret import SecretOauth
from meiduo_practice.utils.views import LoginRequiredJSONMixin


class VerifyEmailView(View):
    def put(self, request):
        # - 1.接收 token
        token = request.GET.get('token')

        if not token:
            return JsonResponse({'code': 400, 'errmsg': 'token缺少'})

        # - 2.解密
        data_dict = SecretOauth().loads(token)

        # - 4.去数据库对比 user_id,email
        try:
            user = User.objects.get(pk=data_dict.get('user_id'), email=data_dict.get('email'))
        except Exception as e:
            # print(e)
            return JsonResponse({'code': 400, 'errmsg': '参数有误!'})

        # - 5.修改激活状态
        user.email_active = True
        user.save()

        return JsonResponse({'code': 0, 'errmsg': '激活成功!'})

class EmailView(View):
    """添加邮箱"""

    def put(self, request):
        """实现添加邮箱逻辑"""
        # 接收参数
        json_dict = json.loads(request.body.decode())
        email = json_dict.get('email')

        # 校验参数
        if not email:
            return JsonResponse({'code': 400, 'errmsg': '缺少email参数'})

        if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
            return JsonResponse({'code': 400, 'errmsg': '参数email有误'})

        # 赋值 email 字段
        try:
            request.user.email = email
            request.user.save()
            verify_url = generate_verify_email_url(request)
            send_verify_email.delay(email, verify_url)
        except Exception as e:
            return JsonResponse({'code': 400, 'errmsg': '添加邮箱失败'})

        # 响应添加邮箱结果
        return JsonResponse({'code': 0, 'errmsg': 'ok'})

class UserInfoView(LoginRequiredJSONMixin, View):
    """用户中心"""

    def get(self, request):
        """提供个人信息界面"""
        return JsonResponse({
            'code': 0,
            'errmsg': '个人中心',
             "info_data":{
                    "username":request.user.username,
                    "mobile": request.user.mobile,
                    "email": request.user.email,
                    "email_active": request.user.email_active
                }
            })

class LogoutView(View):
    """定义退出登录的接口"""

    def delete(self, request):
        """实现退出登录逻辑"""

        # 清理 session
        logout(request)

        # 创建 response 对象.
        response = JsonResponse({'code':0, 'errmsg':'ok'})

        # 调用对象的 delete_cookie 方法, 清除cookie
        response.delete_cookie('username')

        # 返回响应
        return response

class LoginView(View):

    def post(self, request):
        '''实现登录接口'''
        # 1.接收参数
        data_dict = json.loads(request.body.decode())
        username = data_dict.get('username')
        password = data_dict.get('password')
        remembered = data_dict.get('remembered')


        # 2.校验(整体 + 单个)
        if not all([username, password]):
            return JsonResponse({'code': 400,'errmsg': '缺少必传参数'})

        # 实现多账号登录
        # 判断用户输入的账号是用户名还是手机号
        if re.match(r'^1[3-9]\d{9}$', username):
            # 用户输入的账号是手机号:将USERNAME_FIELD指定为'mobile'字段
            User.USERNAME_FIELD = 'mobile'
        else:
            # 用户输入的账号是用户名:将USERNAME_FIELD指定为'username'字段
            User.USERNAME_FIELD = 'username'

        # 3.验证是否能够登录
        user = authenticate(request, username=username, password=password)

        # 判断是否为空,如果为空,返回
        if user is None:
            return JsonResponse({'code': 400, 'errmsg': '用户名或密码错误'})

        # 4.状态保持
        login(request, user)

        # 5.判断是否记住用户
        if remembered != True:
            # 7.如果没有记住: session立刻失效
            request.session.set_expiry(0)
        else:
            # 6.如果记住:  session设置为两周有效
            request.session.set_expiry(None)

        # 8.返回json
        # return JsonResponse({'code': 0, 'errmsg': 'ok'})
        # 前端显示用户名
        # 生成响应对象
        response = JsonResponse({'code': 0, 'errmsg': 'ok'})
        # 在响应对象中设置用户名信息.
        # 将用户名写入到 cookie，有效期 14 天
        response.set_cookie('username', user.username, max_age=3600 * 24 * 14)
        # 返回响应结果
        return response

class RegisterView(View):

    def post(self, request):
        '''接收参数, 保存到数据库'''
        # 1.接收参数：请求体中的JSON数据 request.body
        # json_bytes = request.body # 从请求体中获取原始的JSON数据，bytes类型的
        # json_str = json_bytes.decode() # 将bytes类型的JSON数据，转成JSON字符串
        # json_dict = json.loads(json_str) # 将JSON字符串，转成python的标准字典
        json_dict = json.loads(request.body.decode())

        # 提取参数
        username = json_dict.get('username')
        password = json_dict.get('password')
        password2 = json_dict.get('password2')
        mobile = json_dict.get('mobile')
        allow = json_dict.get('allow')
        sms_code = json_dict.get('sms_code')

        # 2.校验(整体参数是否为空)
        if not all([username, password, password2, mobile, sms_code]):
            return JsonResponse({'code': 400, 'errmsg': '缺少必传参数!'})

        # 3.username检验
        if not re.match('^[a-zA-Z0-9_-]{5,20}$', username):
            return JsonResponse({'code': 400, 'errmsg': '用户名格式有误!'})

        # 4.password检验
        if not re.match('^[a-zA-Z0-9]{8,20}$', password):
            return JsonResponse({'code': 400, 'errmsg': '密码格式有误!'})

        # 5.password2 和 password
        if password != password2:
            return JsonResponse({'code': 400, 'errmsg': '两次输入不对!'})
        # 6.mobile检验
        if not re.match('^1[3-9]\d{9}$', mobile):
            return JsonResponse({'code': 400, 'errmsg': '手机号格式有误!'})
        # 7.allow检验
        if allow != True:
            return JsonResponse({'code': 400, 'errmsg': '勾选同意!'})

        # 判断短信验证码是否正确：跟图形验证码的验证一样的逻辑
        # 提取服务端存储的短信验证码：以前怎么存储，现在就怎么提取
        redis_conn = get_redis_connection('verify_code')
        sms_code_server = redis_conn.get('sms_%s' % mobile)  # sms_code_server是bytes
        # 判断短信验证码是否过期
        if not sms_code_server:
            return JsonResponse({'code': 400, 'errmsg': '短信验证码失效'})
        # 对比用户输入的和服务端存储的短信验证码是否一致
        if sms_code != sms_code_server.decode():
            return JsonResponse({'code': 400, 'errmsg': '短信验证码有误'})

        # 8.注册的核心逻辑-保存到数据库 (username password mobile)
        try:
            user = User.objects.create_user(username=username, password=password, mobile=mobile)
        except Exception as e:
            return JsonResponse({'code': 400, 'errmsg': '注册失败!'})

        # 实现状态保持
        login(request, user)

        # 前端显示用户名
        # 生成响应对象
        response = JsonResponse({'code': 0, 'errmsg': 'ok'})
        # 在响应对象中设置用户名信息.
        # 将用户名写入到 cookie，有效期 14 天
        response.set_cookie('username', user.username, max_age=3600 * 24 * 14)
        # 返回响应结果
        return response

class UsernameCountView(View):
    """判断用户名是否重复注册"""

    def get(self, request, username):
        '''判断用户名是否重复'''
        # 1.查询username在数据库中的个数
        try:
            count = User.objects.filter(username=username).count()
        except Exception as e:
            return JsonResponse({'code': 400, 'errmsg': '查询失败!'})

        # 2.返回结果(json) ---> code & errmsg & count
        return JsonResponse({'code': 0, 'errmsg': '查询成功!', 'count': count})

class MobileCountView(View):

    def get(self, request, mobile):
        '''判断手机号是否重复注册'''
        # 1.查询mobile在mysql中的个数
        try:
            count = User.objects.filter(mobile=mobile).count()
        except Exception as e:
            return JsonResponse({'code': 400, 'errmsg': '查询失败!'})

        # 2.返回结果(json)
        return JsonResponse({'code': 0, 'errmsg': '查询成功!', 'count': count})